#!/usr/bin/env python
# $Id: pyspaceinvaders.py 1.51 2004/08/19 11:57:50 jimb Exp $
# Python Space Invaders.
# Author:   Jim Brooks  http://www.jimbrooks.org
# Date:     2004/08
# License:  GNU General Public License (GPL)
# Requires: Python 2.3, PyGame, SDL.
# Notes:    See notes.txt.
# ==============================================================================
# shootGFW modification
# Contributor: CNBorn <http://cnborn.net>
# Projects on Google Code: http://code.google.com/p/shootgfw/ 


import os, sys, random
import pygame
from pygame.locals import *
from pygame.rect import Rect
if not pygame.font: print "Warning, fonts disabled"
from libgame import *
from libutils import *
from pygame.joystick import *

class RectangularArray:
    def __init__(self, rows, cols, value=0):
        self.arr = [None]*rows
        self.row = [value]*cols
    def __getitem__(self, (i, j)):
        return (self.arr[i] or self.row)[j]
    def __setitem__(self, (i, j), value):
        if self.arr[i]==None:
            self.arr[i] = self.row[:]
        self.arr[i][j] = value


# Colors.
RGBbg        = (0, 0, 0)
RGBtext      = (210, 240, 255)
RGBalive     = (0, 255, 0)
RGBdead      = (255, 0, 0)
RGBgameover  = RGBdead
RGBgreen     = (0,255,0)
RGBcyan      = (0,200,200)

# ------------------------------------------------------------------------------
# Classes.
# ------------------------------------------------------------------------------

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Object class.
class Object:
    def __init__( self ):
        self.valid    = True
        self.hit      = 0
        self.movement = ( 0, 0 )
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Player class.
class Player(Object):
    def __init__( self , st ):
        Object.__init__( self )
        self.image       = pygame.image.load( "img/player.png" )
        self.image2      = pygame.image.load( "img/playerb.png" )
        self.imageHit    = pygame.image.load( "img/explosion.png" )
        self.rect        = self.image.get_rect()
        self.imageFlip   = False
        self.step        = 3 * st.stride
        self.fire        = False
        #Added some Special Weapons.
        self.special_hosts = False
        self.special_people = False
        self.fireLatency = 3
        self.salvo       = 5
        return

    def Reset( self, st, scr ):
        self.valid        = True
        self.hit          = 0 # counts down
        self.rect.centerx = scr.width / 2
        self.rect.bottom  = st.ground
        self.special_hosts = False
        return        

    def Hit( self ):
        self.hit = 30
        st.playerLives -= 1
        if st.playerLives <= 0: # player out of lives?
            st.GameOver()
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Alien class.
class Alien(Object):
    # constants:
    points    = 50
    colCnt    = 15
    rowCnt    = 8
    totalCnt  = colCnt * rowCnt
    # vars:
    imageFlip = False
    horzDir   = -1
    
    def __init__( self, fname, fname2 ):
        Object.__init__( self )
        self.image     = pygame.image.load( fname  )
        self.image2    = pygame.image.load( fname2 )
        self.imageHit  = pygame.image.load( "img/explosion.png" )
        self.rect      = self.image.get_rect()
        # reset vars
        self.imageFlip = False
        self.horzDir   = -1
        return
    
    def Hit( self ):
        self.hit = 7
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Player Magic missile 'fire at will' class.
class PlayerMagicMissile(Object):
    def __init__( self , x):
        Object.__init__( self )
        self.image        = pygame.image.load( "img/missile_player.png" )
        self.rect         = self.image.get_rect()
        self.rect.centerx = x 
        self.rect.centery = st.player.rect.centery - st.player.rect.height
        return
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Player missile class.
class PlayerMissile(Object):
    def __init__( self ):
        Object.__init__( self )
        self.image        = pygame.image.load( "img/missile_player.png" )
        self.rect         = self.image.get_rect()
        self.rect.centerx = st.player.rect.centerx
        self.rect.centery = st.player.rect.centery - st.player.rect.height
        return
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Player Special 'People' class.
class PlayerPeopleSpecial(Object):
    def __init__( self ):
        Object.__init__( self )
        self.image        = pygame.image.load( "img/special_people.png" )
        self.rect         = self.image.get_rect()
        self.rect.centerx = st.player.rect.centerx
        self.rect.centery = 477 
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Player Special 'Hosts' class.
class PlayerSpecial(Object):
    def __init__( self ):
        Object.__init__( self )
        self.image        = pygame.image.load( "img/special_hosts.png" )
        self.rect         = self.image.get_rect()
        self.rect.centerx = st.player.rect.centerx
        self.rect.centery = 295 #st.player.rect.centery - st.player.rect.height
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Alien missile class.
class AlienMissile(Object):
    def __init__( self, alien ):
        Object.__init__( self )
        self.image        = pygame.image.load( "img/missile_alien.png" )
        self.rect         = self.image.get_rect()
        self.rect.centerx = alien.rect.centerx + random.randint( -8, 8 )
        self.rect.centery = alien.rect.centery + alien.rect.height
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Screen state
class Screen:
    # Initialize screen geometry and caption text in title bar.
    def __init__( self, w, h, caption ):
        self.width  = w
        self.height = h
        self.screen = pygame.display.set_mode( (w,h) )
        self.font   = pygame.font.SysFont( None, 28 )
        pygame.display.set_caption( caption )
        return

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Game state
class State:
    # Fundamental game states:
    state_over     = -2  # enum
    state_pause    = -1  # enum
    state_stop     = 0   # enum
    state_play     = 1   # enum
    state          = state_stop

    # Sprites:
    player         = None
    alienColumns   = []
    playerMissiles = []
    playerSpecial = None 
    alienMissiles  = []

    # Misc:
    stride         = 1.0  # effective speed
    tick           = 0
    tempo          = 1
    score          = 0
    level          = 1
    cheat          = 0    # 1: 999 lives 2: 999 lives + persistent gunfire
    ground         = None
    ceiling        = None
    
    # - - - - - - - - -
    # Initialize game state.
    # Pass Screen object as "scr".
    def __init__( self, scr ):
        self.Reset( scr, 1 )
        return

    # - - - - - - - - -
    # Reset game state.
    # Can advance level of difficulty.
    def Reset( self, scr, level ):
        self.tick     = 0
        self.tempo    = 1
        self.score    = 0
        self.level    = level
        if not self.cheat or level == 1:
            self.playerLives = 5
        self.ground   = scr.height - 6
        self.ceiling  = 32

        msg.Del( MsgListGameOver() )

        # Create/reset player.
        if self.player == None:
            self.player = Player( self )
        self.player.Reset( self, scr )

        # Delete all aliens (invalidate then prune).
        if len(self.alienColumns):
            for col in range(Alien.colCnt):
                for alien in self.alienColumns[col]:
                    alien.valid = False
            PruneListList( self.alienColumns )
            
        # Create a full population of aliens.
        self.alienColumns = []
        
        # Create a GFW Array of Aliens.
        self.gfwColumns = RectangularArray(Alien.rowCnt, Alien.colCnt)
        self.gfwColumns[(1,2)] = 1
        self.gfwColumns[(1,4)] = 1
        self.gfwColumns[(2,1)] = 1
        self.gfwColumns[(3,1)] = 1
        self.gfwColumns[(3,3)] = 1
        self.gfwColumns[(4,1)] = 1
        self.gfwColumns[(5,2)] = 1
        self.gfwColumns[(5,3)] = 1
        self.gfwColumns[(5,4)] = 1
        self.gfwColumns[(4,4)] = 1
        
        self.gfwColumns[(1,6)] = 1
        self.gfwColumns[(1,7)] = 1
        self.gfwColumns[(1,8)] = 1
        self.gfwColumns[(2,6)] = 1
        self.gfwColumns[(3,6)] = 1
        self.gfwColumns[(3,7)] = 1
        self.gfwColumns[(3,8)] = 1
        self.gfwColumns[(4,6)] = 1
        self.gfwColumns[(5,6)] = 1

        self.gfwColumns[(1,10)] = 1
        self.gfwColumns[(1,14)] = 1
        self.gfwColumns[(2,10)] = 1
        self.gfwColumns[(2,14)] = 1
        self.gfwColumns[(3,10)] = 1
        self.gfwColumns[(3,12)] = 1
        self.gfwColumns[(4,12)] = 1
        self.gfwColumns[(3,14)] = 1
        self.gfwColumns[(4,10)] = 1
        self.gfwColumns[(4,14)] = 1
        self.gfwColumns[(5,11)] = 1
        self.gfwColumns[(5,13)] = 1

        for col in range(Alien.colCnt):
            self.alienColumns.append( [] )
            for row in range(Alien.rowCnt):
                if self.gfwColumns[(row,col)] == 1:
                    fname  = "img/alien2.png"
                    fname2 = "img/alien2b.png"
                    alien = Alien( fname, fname2 )
                    #This is a densier array setting comparing the original code.
                    alien.rect.move_ip( col * 33 + 30, row * 30 + self.ceiling )
                    self.alienColumns[col].append( alien )

        # Delete any missiles.
        if len(self.playerMissiles):
            for m in self.playerMissiles: m.valid = False
            PruneList( self.playerMissiles )
        # Delete any Specials
        if self.playerSpecial != None:
            self.playerSpecial = None
        if len(self.alienMissiles):
            for m in self.alienMissiles:  m.valid = False
            PruneList( self.alienMissiles )

        return

    # - - - - - - - - -
    def GameOver( self ):
        self.state = self.state_over
        msg.Add( MsgListGameOver() )
        return

    # - - - - - - - - -
    # Toggle pause if playing else do nothing.
    def TogglePause( self ):
        if self.state == self.state_play:
            self.state = self.state_pause
        elif self.state == self.state_pause:
            self.state = self.state_play
        return

    # - - - - - - - - -
    # For convenience, return a single list
    # from the lists of alien columns.
    # NOTE: The list returned is a derivation.
    #       It shouldn't be modified (treat as read-only).
    def AlienList( self ):
        list = []
        for col in range(Alien.colCnt):
            for alien in self.alienColumns[col]:
                list.append( alien )
        return list

# ------------------------------------------------------------------------------
# Subroutines.
# ------------------------------------------------------------------------------

# Missile/missile collisions.
# Detects if one missile has collided into any opposite missiles (plural).
def MissileMissileCollision( missile, missileIdx, oppMissileList ):
    if missile.valid:
        oppMissileIdx = -1
        for oppMissile in oppMissileList:
            oppMissileIdx += 1
            if oppMissile.valid and Collided( missile, oppMissile ):
                missile.valid = False
                oppMissile.valid = False
    return

# Missile/missile collisions.
# Detects if one missile has collided into any opposite missiles (plural).
def MissileSpecialCollision( missile, missileIdx, oppMissileList ):
    if missile.valid:
        oppMissileIdx = -1
        for oppMissile in oppMissileList:
            oppMissileIdx += 1
            if oppMissile.valid and Collided( missile, oppMissile ):
                #missile.valid = False
                oppMissile.valid = False
    return

# Has any alien collided into the player?
def PlayerAlienCollision( alienList ):
    for alien in alienList:
        # Ignore further collisions while both are exploding.
        if alien.valid and Collided( alien, st.player ):
            if alien.hit <= 0 and st.player.hit <= 0:
                alien.Hit()
                st.player.Hit()
    return

# ------------------------------------------------------------------------------
# Render.
# ------------------------------------------------------------------------------

def Render():
    # Clear screen.
    scr.screen.fill( RGBbg )

    # Don't render if stopped.
    if st.state != st.state_stop:
        Render2()

    # Display any text messages (over whatever was rendered).
    msg.Render()

    pygame.display.flip()

    return

def Render2():
    # Blit player.
    if st.player.hit <= 0:
        if st.player.imageFlip:
            scr.screen.blit( st.player.image,  st.player.rect )
        else:
            scr.screen.blit( st.player.image2, st.player.rect )
    else:
        scr.screen.blit( st.player.imageHit, st.player.rect )

    # Blit aliens.
    for alien in st.AlienList():
        if alien.hit <= 0:
            if Alien.imageFlip:
                scr.screen.blit( alien.image, alien.rect )
            else:
                scr.screen.blit( alien.image2, alien.rect )
        else:
                scr.screen.blit( alien.imageHit, alien.rect )

    # Blit player missiles.
    for o in st.playerMissiles:
        if o.valid and o.rect.centery > 0:
            scr.screen.blit( o.image, o.rect )
    # Blit player Special 'Hosts' Move
    if st.playerSpecial != None:
        if st.playerSpecial.valid and st.playerSpecial.rect.centery > 0:
            scr.screen.blit( st.playerSpecial.image, st.playerSpecial.rect )

    # Blit alien missiles.
    for o in st.alienMissiles:
        if o.valid and o.rect.centery < scr.height:
            scr.screen.blit( o.image, o.rect )

    # Show status.
    MsgShowScore()
    MsgShowLevel()
    MsgShowLives()

    return

# ------------------------------------------------------------------------------
# Animate.
# ------------------------------------------------------------------------------

# Main animation function.
# Assumes: invocation driven by timer tick.
def Animate():
    # Periodically prune invalid objects.
    PruneList( st.playerMissiles )
    PruneList( st.alienMissiles )
    PruneListList( st.alienColumns )

    # Animate only if playing.
    if st.state == st.state_play:
        alienList = st.AlienList()
        AnimatePlayer( alienList )
        AnimateAliens( alienList )
        PlayerAlienCollision( alienList )

    return

# Animate player.
def AnimatePlayer( alienList ):
    # Animate exploding player (ok if not hit).
    st.player.hit -= 1

    # Don't let player move while exploding.
    if st.player.hit <= 0:
        # Continue player movement until key released.
        if st.player.movement != (0,0):
            if st.player.rect.left      + st.player.movement[0] > 0 \
               and st.player.rect.right + st.player.movement[0] < scr.width:
                st.player.rect.move_ip( st.player.movement[0], 0 )
                st.player.imageFlip = not st.player.imageFlip
        # Player's gun has a latency period and a limited salvo.
        if st.player.fire and st.tick % st.player.fireLatency == 0 and len(st.playerMissiles) < st.player.salvo:
            st.playerMissiles.append( PlayerMissile() )
        # Player's gun's special moves.
        if st.player.special_people == True and st.tick % st.player.fireLatency == 0 and len(st.playerMissiles) < st.player.salvo:
            for FireAtWill in range(0, scr.width, 33):
                st.playerMissiles.append( PlayerMagicMissile(FireAtWill) )
            st.player.special_people == False
            st.playerSpecial = PlayerPeopleSpecial()
        if st.player.special_hosts == True:
            st.playerSpecial = PlayerSpecial()
        elif st.player.special_people != True :
            st.playerSpecial = None

    #Animate Special Weapons from player.
    #Check the time to release the Special
    #if st.player.special_hosts == True and st.tick % 5 == 0:
    #    st.player.special_hosts == False

    if st.playerSpecial != None:
        st.playerSpecial.rect.centery = st.playerSpecial.rect.centery 
        # Has player's missiles hit any alien?
        # Exclude any hit alien from further collision-detection
        # in order to allow player missiles to fly thru explosion
        # to hit a higher alien.
        for alien in alienList:
            if Collided( st.playerSpecial, alien ) and alien.valid and alien.hit <= 0:
                alien.Hit()
                st.score += Alien.points
                #Special Moves won't disappear after hiting anything.
                #st.playerSpecial.valid = False
        # Has this missile hit any opposite missile?
        MissileSpecialCollision( st.playerSpecial, 1, st.alienMissiles )


    # Animate missiles from player.
    missileIdx = -1
    for missile in st.playerMissiles:
        missileIdx += 1
        # Animate missile.
        missile.rect.centery -= 10 * st.stride
        # Off-screen?
        if missile.rect.top < st.ceiling:
            missile.valid = False # will be pruned later
            continue
        # Has player's missiles hit any alien?
        # Exclude any hit alien from further collision-detection
        # in order to allow player missiles to fly thru explosion
        # to hit a higher alien.
        for alien in alienList:
            if Collided( missile, alien ) and alien.valid and alien.hit <= 0:
                alien.Hit()
                st.score += Alien.points
                if st.cheat != 2: missile.valid = False
        # Has this missile hit any opposite missile?
        MissileMissileCollision( missile, missileIdx, st.alienMissiles )

    return

# Animate aliens (part 1).
def AnimateAliens( alienList ):
    # Animate aliens (unless player is hit/exploding).
    if st.player.hit <= 0:
        # Call actual routine.
        (invaded,alienCnt) = AnimateAliens2( alienList )
        # Game over if aliens have invaded (reached the ground).
        # Or were all aliens destroyed?  If so, goto next level.
        if invaded:
            st.GameOver()
        elif alienCnt == 0:
            st.Reset( scr, st.level + 1 )
    return

# Animate aliens (part 2).
# Returns: (invaded,alienCnt)
# "invaded" true if any alien has reached the ground.
def AnimateAliens2( alienList ):
    invaded = False

    # Animate the walking of aliens.
    if st.tick % 5 == 0:
        Alien.imageFlip = not Alien.imageFlip

    # Only aliens at bottom of columns can fire.
    for list in st.alienColumns:
        if len(list):
            alien = list[-1] # last element (alien at bottom of column)
            if random.randint( 0, 1000 ) > (999 - min(20,2*st.tempo)):
                st.alienMissiles.append( AlienMissile( alien ) )

    # Animate missiles from aliens.
    missileIdx = -1
    for missile in st.alienMissiles:
        missileIdx += 1
        # Animate missile.
        missile.rect.centery += 10 * st.stride
        # Off-screen?
        if missile.rect.bottom > st.ground:
            missile.valid = False # will be pruned later
            continue
        # Has an alien missile hit the player?
        # Ignore further hits while player explodes.
        if Collided( missile, st.player ) and st.player.hit <= 0:
            missile.valid = False
            st.player.Hit()
        # Has this missile hit any opposite missile?
        MissileMissileCollision( missile, missileIdx, st.playerMissiles )

    # Animate alien movement:
    # - right-to-left
    # - down
    # - left-right
    # - down
    # - repeat

    # Move all aliens left or right.
    for alien in alienList:
        alien.rect.centerx += Alien.horzDir * st.tempo * st.stride

    # Has any alien hit the left/right edge of screen?
    hitEdge = False
    padding = 4
    for alien in alienList:
        if alien.rect.left - padding < 0 or alien.rect.right + padding > scr.width:
            hitEdge = True
            break
    if hitEdge:
        # Reverse horizontal direction of aliens.
        Alien.horzDir = -Alien.horzDir
        # Move all aliens downward one step.
        for alien in alienList:
            alien.rect.centery += 4 * st.stride
            # Has this alien invaded (reached the ground)?
            if alien.rect.bottom >= st.ground:
                invaded = True

    # Decrement alien.hit of every alien
    # in order to animate exploding aliens.
    for alien in alienList:
        alien.hit -= 1
        # Subtle: An alien is dead if .hit was decremented from 1 to 0.
        # .hit is assigned a positive value if alien was struck.
        if alien.hit == 0:
            alien.valid = False

    # Increase tempo (alien movement) as the amount of aliens decreases.
    factor = Alien.totalCnt / 4
    st.tempo = min(10,st.level)
    if len(alienList) > 5:
        st.tempo += 4 - int( len(alienList) / factor ) + 1
    else:
        st.tempo += 12 # very quick when few aliens survive

    return (invaded,len(alienList))

# ------------------------------------------------------------------------------
# Specific messages.
# ------------------------------------------------------------------------------

# The reason these are functions is because (x,y) is computed dynamically
# based on screen size.  The functions return a list that contains one tuple.

def MsgListGameOver():
    return [ ( "GAME OVER", scr.width/4.0*3.0, 4, RGBgameover, 0 ) ]

def MsgShowScore():
    msg.Show( ("SCORE: "+str(st.score), 4, 4, RGBtext, 0) )
    return
    
def MsgShowLevel():
    msg.Show( ("LEVEL: "+str(st.level), 16+scr.width/4.0*1.0, 4, RGBtext, 0) )
    #A little modification here.
    msg.Show( ("CNBORN.NET", scr.width/4.0*3.0, 4, RGBtext, 0) )
    return
    
def MsgShowLives():
    if st.playerLives:
        rgb = RGBalive
    else:
        rgb = RGBdead
    msg.Show( ("LIVES: "+str(st.playerLives), scr.width/4.0*2.0, 4, rgb, 0) )
    return

# ------------------------------------------------------------------------------
# Splash.
# ------------------------------------------------------------------------------

class Splash:
    def __init__( self ):
        self.on = True
        self.Enable( self.on )
        return

    def SplashList( self ):
        x = scr.width/2
        y = 8
        return [ ( "PYTHON SPACE INVADERS -- shootGFW",     x, y+32*1, RGBgreen,1 ), \
                 ( "WWW.JIMBROOKS.ORG/PYTHON/", x, y+32*2, RGBcyan, 1 ), \
                 ( "CNBORN.NET", x, y+32*3, RGBcyan, 1 ), \
                 ( "1: START",                  x, y+32*4, RGBtext, 1 ), \
                 ( "Z: LEFT",                   x, y+32*5, RGBtext, 1 ), \
                 ( "X: RIGHT",                  x, y+32*6, RGBtext, 1 ), \
                 ( "RIGHT CTRL: FIRE",          x, y+32*7, RGBtext, 1 ), \
                 ( "ESC: PAUSE",                x, y+32*8, RGBtext, 1 ), \
                 ( "F5, F6: CHEAT, CHEAT MORE", x, y+32*9, RGBtext, 1 ), \
                 ( "Q: QUIT",                   x, y+32*10, RGBtext, 1 )  ]

    def Enable( self, f ):
        if f:
            msg.Add( self.SplashList() )
            self.on = True
        else:
            msg.Del( self.SplashList() )
            self.on = False
        return

    # If stopped, ESC key does nothing (nothing to unpause).
    def Toggle( self ):
        if st.state != st.state_stop:
            self.on = not self.on
            self.Enable(self.on)
        return

# ------------------------------------------------------------------------------
# Initialization.
# ------------------------------------------------------------------------------

random.seed()
pygame.init()
POLLCLOCK = USEREVENT + 1
pygame.time.set_timer ( POLLCLOCK, 40 )
scr    = Screen( 550, 500, "Python Space Invaders -- shootGFW" )
msg    = Msg( scr.screen, scr.font )
st     = State( scr )
splash = Splash()

# ------------------------------------------------------------------------------
# Event loop.
# ------------------------------------------------------------------------------

run = True
while run:
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Process events.
    event = pygame.event.wait()
    # .......................................................
    if event.type == pygame.QUIT:        
        sys.exit()
    # .......................................................
    elif event.type == POLLCLOCK:
        st.tick += 1
        Animate()
        Render()
    # .......................................................
    elif event.type == KEYDOWN:
        # Start game?
        if event.key == K_1:
            st.Reset( scr, 1 )
            st.state = st.state_play
            splash.Enable( False )
        # Quit?
        elif event.key == K_q:
            run = False
        # ESC?
        elif event.key == K_ESCAPE:
            splash.Toggle()
            st.TogglePause()
        
        #----ignore other keys if not playing----
        if st.state != st.state_play:
            continue
        #----ignore other keys if not playing----

        # Move player left?
        if event.key == K_z or event.key == K_LEFT:
            st.player.movement = ( -st.player.step, 0 )
        # Move player right?
        elif event.key == K_x or event.key == K_RIGHT:
            st.player.movement = ( st.player.step, 0 )
        # Player fired gun?
        elif event.key == K_RCTRL or event.key == K_LCTRL:
            st.player.fire = True
        # Test for Supermove
        elif event.key == K_SPACE:
            st.player.special_hosts = True
        elif event.key == K_c:
            st.player.special_people = True
        # Cheat?
        elif event.key == K_F5:
            st.cheat = 1
            st.playerLives = 999
            st.player.salvo = 7
        elif event.key == K_F6:
            st.cheat = 2
            st.playerLives = 999
            st.player.salvo = 12
    # .......................................................
    elif event.type == KEYUP:
        # Stop moving player?
        if event.key == K_z or event.key == K_x or event.key == K_LEFT or event.key == K_RIGHT:
            st.player.movement = ( 0, 0 )
        # Player stopped firing gun?
        elif event.key == K_RCTRL or event.key == K_LCTRL:
            st.player.fire = False
        elif event.key == K_SPACE:
            st.player.special_hosts = False
        elif event.key == K_c:
            st.player.special_people = False
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - -

#--END--
